package control;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
import util.Info;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import util.Info;
/**
 *
 * @author Marek
 */
//TODO: all not default exception should be serviced by doGet, and doPost. Now for example when the null pointer exception is thrown the whole application is shot down and cannot be used, and redeploy is needed. Probably the best scenario is to reset whole servlet when the non default exception is encountered
//TODO: possible optymalization -> Use onle local servlet atributes. Treat servlet as short session statefull, long term stateless, servlet exit sesion finalize
public abstract class AbstractServlet1 extends HttpServlet {

    private ServletConfig config = null;
    private RegisterForms registerForms = null;
    private RegisterActions registerActions = null;

    protected AbstractServlet1() {
        this.config = new ServletConfig();
        this.registerForms = new RegisterForms();
        this.registerActions = new RegisterActions();
        this.construct(this.config, this.registerForms, this.registerActions);
    }

    //TODO Problably i should integrate three following registers into one ServletConfig object :-)
    abstract protected void construct(ServletConfig config, RegisterForms registerForms, RegisterActions registerActions);    //<editor-fold defaultstate="collapsed" desc="Labels used in application">

    abstract protected void beforeExit(HttpSession session, RegisterParameter registerParam, RegisterError registerError);

    /**
     *
     */
    private enum SessionKeysPrivate {

        ____ServletTemplateName,
        ____FormFillingBean,
        ____ActionsRegister,
        ____FormsRegister,
        ____IsInitialized,
        _STATE,
    }

    /**
     *
     */
    public enum SessionKeysPublic {

        errors,
        rparams, action
    }

    /**
     *
     */
    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Methods that can be overriden by subclass">
    /**
     *
     * @param sessionRegister
     * @param parameters
     * @param formRegister
     * @param actionRegister
     * @param apiManager
     * @throws javax.servlet.ServletException
     * @throws AbstractServlet1.BreakProcessException
     * @throws AbstractServlet1.RedirectRequest
     */
    abstract protected void initSesionVars(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, BreakProcessException, RedirectRequest, CleanServletRequest;

    /**
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processActionOne(HttpSession session, RegisterParameter params, RegisterError errors) throws BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("ActionOne is working correctly");
    }

    /**
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processActionTwo(HttpSession session, RegisterParameter params, RegisterError errors) throws BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("ActionTwo is working correctly");
    }

    /**
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processActionThree(HttpSession session, RegisterParameter params, RegisterError errors) throws BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("ActionThree is working correctly");
    }

    /**
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processActionFour(HttpSession session, RegisterParameter params, RegisterError errors) throws BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("ActionFour is working correctly");
    }

    /**
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processActionFive(HttpSession session, RegisterParameter params, RegisterError errors) throws BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("ActionFive is working correctly");
    }

    /**
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processActionSix(HttpSession session, RegisterParameter params, RegisterError errors) throws BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("ActionSix is working correctly");
    }

    /**
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processActionSeven(HttpSession session, RegisterParameter params, RegisterError errors) throws BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("ActionSeven is working correctly");
    }

    /**
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processActionEight(HttpSession session, RegisterParameter params, RegisterError errors) throws BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("ActionEight is working correctly");
    }

    /**
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processActionNine(HttpSession session, RegisterParameter params, RegisterError errors) throws BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("ActionNine is working correctly");
    }

    /**
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processActionTen(HttpSession session, RegisterParameter params, RegisterError errors) throws BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("ActionTen is working correctly");
    }

    /**
     * @param params
     * @param errors
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processFormOne(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("FormOne is working correctly");
    }

    /**
     * @param params
     * @param errors
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processFormTwo(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("FormTwo is working correctly");
    }

    /**
     * @param params
     * @param errors
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processFormThree(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("FormThree is working correctly");
    }

    /**
     * @param params
     * @param errors
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processFormFour(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("FormFour is working correctly");
    }

    /**
     * @param params
     * @param errors
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processFormFive(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("FormFive is working correctly");
    }

    /**
     * @param params
     * @param errors
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processFormSix(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("FormSix is working correctly");
    }

    /**
     * @param params
     * @param errors
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processFormSeven(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("FormSeven is working correctly");
    }

    /**
     * @param params
     * @param errors
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processFormEight(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("FormEight is working correctly");
    }

    /**
     * @param params
     * @param errors
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processFormNine(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("FormNine is working correctly");
    }

    /**
     * @param params
     * @param errors
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    protected void processFormTen(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest {
        System.out.println("FormTen is working correctly");
    }

    /**
     * @param sessionMemoryLoad
     * @param errors
     * @param parameters
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    abstract protected void load(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest;

    /**
     * @param sessionMemorySave
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     * @throws AbstractServlet1.RedirectRequest
     * @throws AbstractServlet1.BreakProcessException
     */
    abstract protected void save(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest;
    //</editor-fold>

    private void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession(true);
        State state = (State) session.getAttribute(SessionKeysPrivate._STATE.name());
        try {
            if (state == null || !state.prevServlet.equals(this.config.servletName) || session.isNew()) {
                System.out.println("Cleaning state");
                if (null != state) {
                    this.beforeExit(session, state.registerParameter, state.registerError);
                }
                state = new State();
                state.prevServlet = this.config.servletName;
                state.registerParameter.saveAll(request);
                this.initSesionVars(session, state.registerParameter, state.registerError);
                session.setAttribute(SessionKeysPrivate._STATE.name(), state);
                session.setAttribute(SessionKeysPublic.errors.name(), state.registerError.getErrorsCollection());
                session.setAttribute(SessionKeysPublic.rparams.name(), state.registerParameter.getCollectionOfParameters());
            } else {
                state.registerParameter.saveAll(request);
            }
            this.load(session, state.registerParameter, state.registerError);
            switch (request.getMethod()) {
                case "GET":
                    if (true == state.registerParameter.doParameterExist(SessionKeysPublic.action.name())) {//Here should be used new method isAction instead of this metod
                        this.registerActions.processAction(session, state.registerParameter, state.registerError);
                        throw new RedirectRequest(request.getHeader("referer"));
                    } else {
                        APIManager.printAPI(this.config.templateName, request, response);
                    }
                    break;
                case "POST":
                    this.registerForms.processForm(session, state.registerParameter, state.registerError);
                    throw new RedirectRequest(request.getHeader("referer"));
            }
            this.save(session, state.registerParameter, state.registerError);
        } catch (CleanServletRequest e) {
            this.beforeExit(session, state.registerParameter, state.registerError);
            session.setAttribute(SessionKeysPrivate._STATE.name(), null);
            String redirectTo = e.getMessage();
            RedirectManager.doRedirect(redirectTo, session, response);
        } catch (BreakProcessException e) {
            String redirectTo = e.getRedirectTo();
            RedirectManager.doRedirect(redirectTo, session, response);
        } catch (RedirectRequest e) {
            String redirectTo = e.getMessage();
            RedirectManager.doRedirect(redirectTo, session, response);
        }
        state.registerParameter.deleteParameter(SessionKeysPublic.action.name());
        session.setAttribute(SessionKeysPrivate._STATE.name(), state);
        session.setAttribute(SessionKeysPublic.errors.name(), state.registerError.getErrorsCollection());
        session.setAttribute(SessionKeysPublic.rparams.name(), state.registerParameter.getCollectionOfParameters());

    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles following requests: Prints the API for the first time, Prints the
     * actualized API, after the action had been performed,Prints the actualized
     * API, after form had been send, d Handle actions,
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.processRequest(request, response);
    }

    /**
     * Handles following requests: Handles sent forms requests
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "";
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="AbstractServlet1 compositions.">
    /**
     *
     */
    final protected class RegisterSession implements Serializable {

        private Set<String> keysRegister = new HashSet<>();
        private HttpSession session = null;

        private RegisterSession(HttpSession session) {
            this.session = session;
        }

        public void registerVar(String key, Object object) {
            keysRegister.add(key);
            session.setAttribute(key, object);
        }

        public void unregisterVar(String key) {
            keysRegister.remove(key);
            session.removeAttribute(key);
        }

        public void cleanRegister() {
            Iterator<String> iterator = keysRegister.iterator();
            while (iterator.hasNext()) {
                session.removeAttribute(iterator.next());
            }
            keysRegister.clear();
        }

        public boolean checkVar(String key) {
            return keysRegister.contains(key);
        }
    }

    /**
     *
     */
    final protected class RegisterSessionLoad implements Serializable {

        private RegisterSession registerSession = null;

        private RegisterSessionLoad(RegisterSession registerSession) {
            this.registerSession = registerSession;
        }

        public Object loadVar(String key) throws ServletException {
            if (true == this.registerSession.checkVar(key)) {
                return this.registerSession.session.getAttribute(key);
            } else {
                throw new ServletException("SessionMemoryLoad->loadVar(): Key " + key + " wasn't registered in the SessionRegister object.");
            }
        }
    }

    /**
     *
     */
    final protected class RegisterSessionSave implements Serializable {

        private RegisterSession registerSession = null;

        private RegisterSessionSave(RegisterSession registerSession) {
            this.registerSession = registerSession;
        }

        public void saveVar(String key, Object object) throws ServletException {
            if (true == this.registerSession.checkVar(key)) {
                this.registerSession.session.setAttribute(key, object);
            } else {
                throw new ServletException("SessionMemorySave->saveVar(): Key " + key + " wasn't registered in the SessionRegister object.");
            }
        }
    }

    /**
     *
     */
    final protected class RegisterError implements Serializable {

        private RegisterError() {
        }

        private HashMap<String, String> errors = new HashMap<>();

        protected void registerError(String key, String message) {
            this.errors.put(key, message);
        }

        protected void unregisterError(String key) {
            this.errors.remove(key);
        }

        protected void clearErrors() {
            this.errors.clear();
        }

        protected boolean areErrors() {
            return !this.errors.isEmpty();
        }

        private Map<String, String> getErrorsCollection() {
            final Map<String, String> map = Collections.unmodifiableMap(new HashMap<String, String>(this.errors));
            return map;
        }

    }

    /**
     *
     */
    final protected class RegisterParameter implements Serializable {

        private RegisterParameter() {
        }

        private HashMap<String, String[]> parameters = new HashMap<>();

        private void saveAll(HttpServletRequest request) throws ServletException {
            Enumeration<String> keys = request.getParameterNames();
            while (keys.hasMoreElements()) {
                String key = keys.nextElement();
                this.saveParameter(key, request.getParameterValues(key));
            }
        }

        private void saveParameter(String key, String[] values) throws ServletException {
            try {
                String[] notEncodedArray = values;
                String[] encodedArray = new String[notEncodedArray.length];
                for (int x = 0; x < notEncodedArray.length; x++) {
                    encodedArray[x] = new String(notEncodedArray[x].getBytes("iso-8859-1"), "UTF-8");
                }
                this.parameters.put(key, encodedArray);
            } catch (UnsupportedEncodingException ex) {
                throw new ServletException("readParameter():UnsupportedEncodingException");
            }
        }

        protected String[] readParameter(String key) {
            return this.parameters.get(key);
        }

        protected void deleteParameter(String key) {
            this.parameters.remove(key);
        }

        protected void clearAll() {
            this.parameters.clear();
        }

        protected boolean doParameterExist(String key) {
            return this.parameters.containsKey(key);
        }

        protected Map<String, String[]> getCollectionOfParameters() {
            final Map<String, String[]> map = Collections.unmodifiableMap(new HashMap<String, String[]>(this.parameters));
            return map;
        }
    }

    /**
     *
     */
    protected enum ActionKey {

        processActionOne,
        processActionTwo,
        processActionThree,
        processActionFour,
        processActionFive,
        processActionSix,
        processActionSeven,
        processActionEight,
        processActionNine,
        processActionTen
    }

    final protected class RegisterActions implements Serializable {

        private HashMap<String, ActionKey> actions = new HashMap<>();

        private void processAction(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest {
            String action = (String) params.readParameter("action")[0];
            ActionKey actionName = actions.get(action);
            if (null == actionName) {
                throw new ServletException("Action " + action + " is not registered in ActionRegister");
            }
            if (ActionKey.processActionOne == actionName) {
                processActionOne(session, params, errors);
            }
            if (ActionKey.processActionTwo == actionName) {
                processActionTwo(session, params, errors);
            }
            if (ActionKey.processActionThree == actionName) {
                processActionThree(session, params, errors);
            }
            if (ActionKey.processActionFour == actionName) {
                processActionFour(session, params, errors);
            }
            if (ActionKey.processActionFive == actionName) {
                processActionFive(session, params, errors);
            }
            if (ActionKey.processActionSix == actionName) {
                processActionSix(session, params, errors);
            }
            if (ActionKey.processActionSeven == actionName) {
                processActionSeven(session, params, errors);
            }
            if (ActionKey.processActionEight == actionName) {
                processActionEight(session, params, errors);
            }
            if (ActionKey.processActionNine == actionName) {
                processActionNine(session, params, errors);
            }
            if (ActionKey.processActionTen == actionName) {
                processActionTen(session, params, errors);
            }
        }

        protected void registerAction(String key, ActionKey actionName) {
            actions.put(key, actionName);
        }

        protected void removeAction(String key) {
            actions.remove(key);
        }
    }

    protected enum FormKey {

        processFormOne,
        processFormTwo,
        processFormThree,
        processFormFour,
        processFormFive,
        processFormSix,
        processFormSeven,
        processFormEight,
        processFormNine,
        processFormTen
    }

    /**
     *
     */
    final protected class RegisterForms implements Serializable {

        private HashMap<String, FormKey> forms = new HashMap<>();

        private void processForm(HttpSession session, RegisterParameter params, RegisterError errors) throws ServletException, IOException, BreakProcessException, RedirectRequest, CleanServletRequest {
            String form = (String) params.readParameter("formName")[0];
            FormKey formName = forms.get(form);
            if (null == formName) {
                throw new ServletException("Form " + form + " is not registered in FormRegister");
            }
            if (FormKey.processFormOne == formName) {
                processFormOne(session, params, errors);
            }
            if (FormKey.processFormTwo == formName) {
                processFormTwo(session, params, errors);
            }
            if (FormKey.processFormThree == formName) {
                processFormThree(session, params, errors);
            }
            if (FormKey.processFormFour == formName) {
                processFormFour(session, params, errors);
            }
            if (FormKey.processFormFive == formName) {
                processFormFive(session, params, errors);
            }
            if (FormKey.processFormSix == formName) {
                processFormSix(session, params, errors);
            }
            if (FormKey.processFormSeven == formName) {
                processFormSeven(session, params, errors);
            }
            if (FormKey.processFormEight == formName) {
                processFormEight(session, params, errors);
            }
            if (FormKey.processFormNine == formName) {
                processFormNine(session, params, errors);
            }
            if (FormKey.processFormTen == formName) {
                processFormTen(session, params, errors);
            }
        }

        protected void registerForm(String key, FormKey formName) {
            forms.put(key, formName);
        }

        protected void removeForm(String key) {
            forms.remove(key);
        }
    }

    /**
     *
     *
     */
    protected class BreakProcessException extends RedirectRequest {

        private String redirectTo = null;

        public BreakProcessException(String message, String redirectTo) {
            super(message);
            this.redirectTo = redirectTo;
        }

        public String getRedirectTo() {
            return this.redirectTo;
        }
    }

    /**
     *
     */
    protected class CleanServletRequest extends RedirectRequest {

        public CleanServletRequest(String message) {
            super(message);
        }
    }

    /**
     *
     */
    protected class RedirectRequest extends Exception {

        public RedirectRequest(String message) {
            super(message);
        }
    }

    /**
     *
     */
    static private class APIManager {

        static private void printAPI(String templateName, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            request.getRequestDispatcher("WEB-INF/" + templateName).include(request, response);
        }
    }

    /**
     *
     */
    static private class RedirectManager {

        static private void doRedirect(String location, HttpSession session, HttpServletResponse response) throws IOException {
            System.out.println("I'm sending redirect to location:" + location);
            if (null != location && !location.equals("")) {
                session.setAttribute("JSPREDIRECTTO", location);
                response.sendRedirect(location);
            } else {
                //TODO: What should function do, when location is null? Should it thrown an axception, or should it did nothing?
            }
        }
    }

    /**
     * Main structure of the AbstractServlet used as easy way to save, and load
     * AbstractServlet1 state in session
     */
    //TODO: Put this to consideration -> Maybe composition should be an EJB class injected by CDI?
    final private class State implements Serializable {

        private String prevServlet = null;
        private RegisterParameter registerParameter = new RegisterParameter();
        private RegisterError registerError = new RegisterError();

        private State() {
        }
    }

    final protected class ServletConfig {

        private String templateName = null;
        private String servletName = null;

        protected void setServletName(String name) {
            servletName = name;
        }

        protected void setTemplateName(String name) {
            templateName = name;
        }
    }

    static public class FormInfo {

        private final String name;

        protected FormInfo(String formName) {
            this.name = formName;
        }

        public String getName() {
            return this.name;
        }
    }

    static public class FormButton {

        private final String name;
        private final String action;
        private final String type;

        protected FormButton(String name, String action, String type) {
            this.name = name;
            this.action = action;
            this.type = type;
        }

        public String getName() {
            return this.name;
        }

        public String getAction() {
            return this.action;
        }

        public String getType() {
            return this.getType();
        }
    }

    static public class FormField {

        private final String name;
        private final String type;
        private final String validate;
        private final String size;
        private final String description;
        private final String value;

        protected FormField(String name, String description, String value, String type, String validate, String size) {
            this.name = name;
            this.type = type;
            this.size = size;
            this.validate = validate;
            this.description = description;
            this.value = value;

        }

        /**
         * @return the name
         */
        public String getName() {
            return name;
        }

        /**
         * @return the type
         */
        public String getType() {
            return type;
        }

        /**
         * @return the validate
         */
        public String getValidate() {
            return validate;
        }

        /**
         * @return the size
         */
        public String getSize() {
            return size;
        }

        /**
         * @return the description
         */
        public String getDescription() {
            return description;
        }

        /**
         * @return the value
         */
        public String getValue() {
            return value;
        }
    }

    static public final class FormGenerator {

        static public FormInfo getFormInfo(Object object) {
            return new FormInfo(object.getClass().toString());
        }

        static public List<FormField> getFormFields(Object object) {
            Method[] methods = object.getClass().getMethods();
            Class<?> c = object.getClass();
            List<FormField> list = new ArrayList<>();
            int cnt = 0;
            for (int x = 0; x < methods.length; x++) {
                list.add(null);
            }
            for (Method method : methods) {
                String methodName = method.getName();
                int methodModifier = method.getModifiers();

                if (Modifier.isPublic(methodModifier) && methodName.startsWith("get")) {
                    if (!Info.descriptionExist(c, methodName)) {
                        continue;
                    }
                    String description = Info.getDescription(c, methodName);
                    int order = Info.getOrder(c, methodName);

                    String tmp = method.getName().replace("get", "");
                    char chars[] = tmp.toCharArray();
                    chars[0] = Character.toLowerCase(chars[0]);
                    methodName = new String(chars);

                    System.out.print(method.getName());
                    //System.out.println("Method description:"+c.Info.getDescription(methodName));
                    System.out.println("Method is setter");
                    System.out.println("Method is public");
                    System.out.println("Method return type is:" + method.getReturnType().toString());
                    System.out.println("--------------");

                    FormField formField;
                    try {
                        String value = "" + method.invoke(object, null);
                        if(value.equals("null")){
                            value = "";
                        }
                        formField = new FormField(methodName, description,value, "", "", "");
                        list.set(order, formField);
                        cnt++;
                    } catch (IllegalAccessException ex) {
                        Logger.getLogger(AbstractServlet1.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (IllegalArgumentException ex) {
                        Logger.getLogger(AbstractServlet1.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (InvocationTargetException ex) {
                        Logger.getLogger(AbstractServlet1.class.getName()).log(Level.SEVERE, null, ex);
                    }

                }

            }
            for (int x = 0; x < list.size(); x++) {
                if (list.get(x) == null) {
                    list.remove(x);
                } else {
                }
            }

            return list.subList(0, cnt);
        }

        static public FormButton[] getFormButtons() {
            return new FormButton[]{new FormButton("test", "test", "test"), new FormButton("test1", "test1", "test1")};
        }

        static public Object updateEntity(Object object, RegisterParameter registerParameter) {
            Object[] okeys = registerParameter.parameters.keySet().toArray();
            for (Object okey : okeys) {
                String key = (String) okey;
                if (key.equals("formName")) {
                    continue;
                }
                char[] chars = key.toCharArray();
                chars[0] = Character.toUpperCase(chars[0]);
                String tmpString = new String(chars);
                String methodName = "set" + tmpString;
                if (!Info.descriptionExist(object.getClass(), "get" + tmpString)) {
                    continue;
                }

                try {
                    Class<?>[] classes = new Class<?>[1];
                    classes[0] = Info.getType(object.getClass(), "get" + tmpString);
                    Method method = object.getClass().getMethod(methodName, classes);
                    System.out.println("setter:" + methodName);
                    System.out.println("Type:" + Info.getType(object.getClass(), "get" + tmpString).toString());
                    if(classes[0]==Long.class) {
                        Long[] parameters = new Long[1];
                        parameters[0] = Long.parseLong(registerParameter.readParameter(key)[0]);
                        method.invoke(object,parameters);
                    }
                    if(classes[0]==String.class) {
                        String[] parameters = new String[1];
                        parameters[0] = registerParameter.readParameter(key)[0];
                        method.invoke(object,parameters);
                    }    
                    
                } catch (NoSuchMethodException ex) {
                    Logger.getLogger(AbstractServlet1.class.getName()).log(Level.SEVERE, null, ex);
                } catch (SecurityException ex) {
                    Logger.getLogger(AbstractServlet1.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalAccessException ex) {
                    Logger.getLogger(AbstractServlet1.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalArgumentException ex) {
                    Logger.getLogger(AbstractServlet1.class.getName()).log(Level.SEVERE, null, ex);
                } catch (InvocationTargetException ex) {
                    Logger.getLogger(AbstractServlet1.class.getName()).log(Level.SEVERE, null, ex);
                }

                //Method method = object.getClass().getMethod(key, parameterTypes)
            }

            return object;
        }
        //getActualizedEntity        
    }

//</editor-fold>
}
